package wxcloud

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"time"
)

const (
	// 微信云存储HTTP API地址
	uploadFileURL      = "https://api.weixin.qq.com/tcb/uploadfile"
	batchDownloadURL   = "https://api.weixin.qq.com/tcb/batchdownloadfile"
	batchDeleteFileURL = "https://api.weixin.qq.com/tcb/batchdeletefile"
)

// UploadFileRequest 获取上传链接的请求结构
type UploadFileRequest struct {
	Env  string `json:"env"`  // 云环境ID
	Path string `json:"path"` // 上传路径, 包含文件名
}

// UploadFileResponse 获取上传链接的响应结构
type UploadFileResponse struct {
	ErrCode       int    `json:"errcode"`
	ErrMsg        string `json:"errmsg"`
	URL           string `json:"url"`           // 上传链接
	Token         string `json:"token"`         // 上传凭证
	Authorization string `json:"authorization"` // 授权信息
	FileID        string `json:"file_id"`       // 文件ID
	CosFileID     string `json:"cos_file_id"`   // COS文件ID
}

// DownloadFileItem 下载文件项
type DownloadFileItem struct {
	FileID string `json:"fileid"`  // 文件ID
	MaxAge int64  `json:"max_age"` // 下载链接有效期（秒）
}

// BatchDownloadRequest 批量获取下载链接的请求结构
type BatchDownloadRequest struct {
	Env      string             `json:"env"`       // 云环境ID
	FileList []DownloadFileItem `json:"file_list"` // 文件列表
}

// DownloadFileResult 下载文件结果
type DownloadFileResult struct {
	FileID      string `json:"fileid"`       // 文件ID
	DownloadURL string `json:"download_url"` // 下载链接
	Status      int    `json:"status"`       // 状态码
	ErrMsg      string `json:"errmsg"`       // 错误信息
}

// BatchDownloadResponse 批量获取下载链接的响应结构
type BatchDownloadResponse struct {
	ErrCode  int                  `json:"errcode"`
	ErrMsg   string               `json:"errmsg"`
	FileList []DownloadFileResult `json:"file_list"`
}

// DeleteFileItem 删除文件项
type DeleteFileItem struct {
	FileID string `json:"fileid"` // 文件ID
}

// BatchDeleteRequest 批量删除文件的请求结构
type BatchDeleteRequest struct {
	Env      string           `json:"env"`       // 云环境ID
	FileList []DeleteFileItem `json:"file_list"` // 文件列表
}

// DeleteFileResult 删除文件结果
type DeleteFileResult struct {
	FileID string `json:"fileid"` // 文件ID
	Status int    `json:"status"` // 状态码
	ErrMsg string `json:"errmsg"` // 错误信息
}

// BatchDeleteResponse 批量删除文件的响应结构
type BatchDeleteResponse struct {
	ErrCode  int                `json:"errcode"`
	ErrMsg   string             `json:"errmsg"`
	FileList []DeleteFileResult `json:"file_list"`
}

// StorageInfo 存储信息
type StorageInfo struct {
	FileID      string    `json:"file_id"`      // 文件ID
	FileName    string    `json:"file_name"`    // 文件名
	FilePath    string    `json:"file_path"`    // 文件路径
	FileSize    int64     `json:"file_size"`    // 文件大小
	UploadTime  time.Time `json:"upload_time"`  // 上传时间
	DownloadURL string    `json:"download_url"` // 下载链接
	MaxAge      int64     `json:"max_age"`      // 链接有效期
}

// GetUploadURL 获取文件上传链接
func (w *WxCloudClient) GetUploadURL(ctx context.Context, fileName string) (*UploadFileResponse, error) {
	token, err := w.AccessToken(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to get access token: %w", err)
	}

	req := UploadFileRequest{
		Env:  w.envId,
		Path: fileName,
	}

	reqBody, err := json.Marshal(req)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	url := fmt.Sprintf("%s?access_token=%s", uploadFileURL, token)

	httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(reqBody))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	httpReq.Header.Set("Content-Type", "application/json")

	resp, err := w.httpClient.Do(httpReq)
	if err != nil {
		return nil, fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	var uploadResp UploadFileResponse
	if err := json.NewDecoder(resp.Body).Decode(&uploadResp); err != nil {
		return nil, fmt.Errorf("failed to decode response: %w", err)
	}

	if uploadResp.ErrCode != 0 {
		return nil, fmt.Errorf("get upload url error: code=%d, msg=%s", uploadResp.ErrCode, uploadResp.ErrMsg)
	}

	return &uploadResp, nil
}

// GetDownloadURL 获取单个文件的下载链接
func (w *WxCloudClient) GetDownloadURL(ctx context.Context, fileID string, maxAge int64) (string, error) {
	urls, err := w.GetDownloadURLs(ctx, []DownloadFileItem{{FileID: fileID, MaxAge: maxAge}})
	if err != nil {
		return "", err
	}

	if len(urls) == 0 {
		return "", fmt.Errorf("no download url returned")
	}

	result := urls[0]
	if result.Status != 0 {
		return "", fmt.Errorf("get download url failed: %s", result.ErrMsg)
	}

	return result.DownloadURL, nil
}

// GetDownloadURLs 批量获取文件下载链接
func (w *WxCloudClient) GetDownloadURLs(ctx context.Context, files []DownloadFileItem) ([]DownloadFileResult, error) {
	token, err := w.AccessToken(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to get access token: %w", err)
	}

	req := BatchDownloadRequest{
		Env:      w.envId,
		FileList: files,
	}

	reqBody, err := json.Marshal(req)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	url := fmt.Sprintf("%s?access_token=%s", batchDownloadURL, token)

	httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(reqBody))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	httpReq.Header.Set("Content-Type", "application/json")

	resp, err := w.httpClient.Do(httpReq)
	if err != nil {
		return nil, fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	var downloadResp BatchDownloadResponse
	if err := json.NewDecoder(resp.Body).Decode(&downloadResp); err != nil {
		return nil, fmt.Errorf("failed to decode response: %w", err)
	}

	if downloadResp.ErrCode != 0 {
		return nil, fmt.Errorf("get download urls error: code=%d, msg=%s", downloadResp.ErrCode, downloadResp.ErrMsg)
	}

	return downloadResp.FileList, nil
}

// DeleteFile 删除单个文件
func (w *WxCloudClient) DeleteFile(ctx context.Context, fileID string) error {
	results, err := w.DeleteFiles(ctx, []string{fileID})
	if err != nil {
		return err
	}

	if len(results) == 0 {
		return fmt.Errorf("no delete result returned")
	}

	result := results[0]
	if result.Status != 0 {
		return fmt.Errorf("delete file failed: %s", result.ErrMsg)
	}

	return nil
}

// UploadFile 上传文件到微信云存储
// filePath: 云存储中的文件路径（包含文件名）
// data: 文件数据字节数组
// 返回上传响应信息和错误
func (w *WxCloudClient) UploadFile(ctx context.Context, uploadResp *UploadFileResponse, filePath string, data []byte) error {
	// 2. 创建 multipart/form-data 请求体
	var buf bytes.Buffer
	writer := multipart.NewWriter(&buf)

	// 设置表单字段
	// key 字段：文件路径
	if err := writer.WriteField("key", filePath); err != nil {
		return fmt.Errorf("failed to write key field: %w", err)
	}

	// Signature 字段：签名信息
	if err := writer.WriteField("Signature", uploadResp.Authorization); err != nil {
		return fmt.Errorf("failed to write Signature field: %w", err)
	}
	if err := writer.WriteField("x-cos-security-token", uploadResp.Token); err != nil {
		return fmt.Errorf("failed to write x-cos-security-token field: %w", err)
	}
	if err := writer.WriteField("x-cos-meta-fileid", uploadResp.CosFileID); err != nil {
		return fmt.Errorf("failed to write x-cos-meta-fileid field: %w", err)
	}

	// file 字段：文件内容
	fileWriter, err := writer.CreateFormFile("file", filePath)
	if err != nil {
		return fmt.Errorf("failed to create file field: %w", err)
	}
	if _, err := fileWriter.Write(data); err != nil {
		return fmt.Errorf("failed to write file data: %w", err)
	}

	// 关闭 multipart writer
	if err := writer.Close(); err != nil {
		return fmt.Errorf("failed to close multipart writer: %w", err)
	}

	// 3. 创建上传请求
	req, err := http.NewRequestWithContext(ctx, "POST", uploadResp.URL, &buf)
	if err != nil {
		return fmt.Errorf("failed to create upload request: %w", err)
	}

	// 4. 设置 Content-Type 为 multipart/form-data
	req.Header.Set("Content-Type", writer.FormDataContentType())

	// 5. 执行文件上传
	resp, err := w.httpClient.Do(req)
	if err != nil {
		return fmt.Errorf("failed to upload file: %w", err)
	}
	defer resp.Body.Close()

	// 6. 检查上传结果
	if resp.StatusCode >= 400 {
		bodyBytes, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("upload failed with status %d: %s", resp.StatusCode, string(bodyBytes))
	}

	// 7. 上传成功，返回包含文件ID等信息的响应
	return nil
}

// DeleteFiles 批量删除文件
func (w *WxCloudClient) DeleteFiles(ctx context.Context, fileIDs []string) ([]DeleteFileResult, error) {
	token, err := w.AccessToken(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to get access token: %w", err)
	}

	files := make([]DeleteFileItem, len(fileIDs))
	for i, fileID := range fileIDs {
		files[i] = DeleteFileItem{FileID: fileID}
	}

	req := BatchDeleteRequest{
		Env:      w.envId,
		FileList: files,
	}

	reqBody, err := json.Marshal(req)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	url := fmt.Sprintf("%s?access_token=%s", batchDeleteFileURL, token)

	httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(reqBody))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	httpReq.Header.Set("Content-Type", "application/json")

	resp, err := w.httpClient.Do(httpReq)
	if err != nil {
		return nil, fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	var deleteResp BatchDeleteResponse
	if err := json.NewDecoder(resp.Body).Decode(&deleteResp); err != nil {
		return nil, fmt.Errorf("failed to decode response: %w", err)
	}

	if deleteResp.ErrCode != 0 {
		return nil, fmt.Errorf("delete files error: code=%d, msg=%s", deleteResp.ErrCode, deleteResp.ErrMsg)
	}

	return deleteResp.FileList, nil
}

// GenerateCloudPath 生成云存储路径
func GenerateCloudPath(dir, fileName string) string {
	timestamp := time.Now().Format("20060102150405")
	if dir == "" {
		return fmt.Sprintf("%s_%s", timestamp, fileName)
	}
	return fmt.Sprintf("%s/%s_%s", dir, timestamp, fileName)
}

// ParseFileIDToPath 从文件ID中解析出路径
func ParseFileIDToPath(fileID string) string {
	// 文件ID格式通常为: cloud://env-id.xxx/path/filename
	// 这里简化处理，提取路径部分
	if len(fileID) > 0 {
		// 查找最后一个 '/' 的位置
		for i := len(fileID) - 1; i >= 0; i-- {
			if fileID[i] == '/' {
				return fileID[i+1:]
			}
		}
	}
	return fileID
}

// UploadFileHelper 上传文件辅助函数，封装完整的上传流程
type UploadFileHelper struct {
	client *WxCloudClient
}

// NewUploadFileHelper 创建上传文件辅助器
func NewUploadFileHelper(client *WxCloudClient) *UploadFileHelper {
	return &UploadFileHelper{client: client}
}

// PrepareUpload 准备上传，获取上传链接和相关信息
func (h *UploadFileHelper) PrepareUpload(ctx context.Context, dir, fileName string) (*StorageInfo, error) {
	cloudPath := GenerateCloudPath(dir, fileName)

	uploadInfo, err := h.client.GetUploadURL(ctx, fileName)
	if err != nil {
		return nil, fmt.Errorf("failed to get upload url: %w", err)
	}

	return &StorageInfo{
		FileID:     uploadInfo.FileID,
		FileName:   fileName,
		FilePath:   cloudPath,
		UploadTime: time.Now(),
	}, nil
}

// GetFileDownloadInfo 获取文件下载信息
func (h *UploadFileHelper) GetFileDownloadInfo(ctx context.Context, fileID string, maxAge int64) (*StorageInfo, error) {
	if maxAge <= 0 {
		maxAge = 7200 // 默认2小时
	}

	downloadURL, err := h.client.GetDownloadURL(ctx, fileID, maxAge)
	if err != nil {
		return nil, fmt.Errorf("failed to get download url: %w", err)
	}

	return &StorageInfo{
		FileID:      fileID,
		FileName:    ParseFileIDToPath(fileID),
		DownloadURL: downloadURL,
		MaxAge:      maxAge,
	}, nil
}

// StorageManager 存储管理器，提供高级存储操作
type StorageManager struct {
	client *WxCloudClient
	helper *UploadFileHelper
}

// NewStorageManager 创建存储管理器
func NewStorageManager(client *WxCloudClient) *StorageManager {
	return &StorageManager{
		client: client,
		helper: NewUploadFileHelper(client),
	}
}

// PrepareFileUpload 准备文件上传
func (sm *StorageManager) PrepareFileUpload(ctx context.Context, dir, fileName string) (*StorageInfo, error) {
	return sm.helper.PrepareUpload(ctx, dir, fileName)
}

// GetFileDownloadURL 获取文件下载链接
func (sm *StorageManager) GetFileDownloadURL(ctx context.Context, fileID string, maxAge int64) (string, error) {
	return sm.client.GetDownloadURL(ctx, fileID, maxAge)
}

// GetFileInfo 获取文件信息
func (sm *StorageManager) GetFileInfo(ctx context.Context, fileID string, maxAge int64) (*StorageInfo, error) {
	return sm.helper.GetFileDownloadInfo(ctx, fileID, maxAge)
}

// DeleteFileByID 根据文件ID删除文件
func (sm *StorageManager) DeleteFileByID(ctx context.Context, fileID string) error {
	return sm.client.DeleteFile(ctx, fileID)
}

// BatchGetDownloadURLs 批量获取下载链接
func (sm *StorageManager) BatchGetDownloadURLs(ctx context.Context, fileIDs []string, maxAge int64) (map[string]string, error) {
	if maxAge <= 0 {
		maxAge = 7200 // 默认2小时
	}

	files := make([]DownloadFileItem, len(fileIDs))
	for i, fileID := range fileIDs {
		files[i] = DownloadFileItem{
			FileID: fileID,
			MaxAge: maxAge,
		}
	}

	results, err := sm.client.GetDownloadURLs(ctx, files)
	if err != nil {
		return nil, err
	}

	urlMap := make(map[string]string)
	for _, result := range results {
		if result.Status == 0 {
			urlMap[result.FileID] = result.DownloadURL
		}
	}

	return urlMap, nil
}

// BatchDeleteFiles 批量删除文件
func (sm *StorageManager) BatchDeleteFiles(ctx context.Context, fileIDs []string) error {
	results, err := sm.client.DeleteFiles(ctx, fileIDs)
	if err != nil {
		return err
	}

	// 检查是否所有文件都删除成功
	for _, result := range results {
		if result.Status != 0 {
			return fmt.Errorf("failed to delete file %s: %s", result.FileID, result.ErrMsg)
		}
	}

	return nil
}
